package com.tinysand.advert.service.impl;

import com.tinysand.advert.constant.SystemConstant;
import com.tinysand.advert.entity.AdvertPlan;
import com.tinysand.advert.entity.AdvertUnit;
import com.tinysand.advert.entity.condition.AdUnitDistrict;
import com.tinysand.advert.entity.condition.AdUnitInterest;
import com.tinysand.advert.entity.condition.AdUnitKeyWord;
import com.tinysand.advert.entity.condition.AdvertUnitRelation;
import com.tinysand.advert.exception.AdvertException;
import com.tinysand.advert.repository.*;
import com.tinysand.advert.service.AdUnitService;
import com.tinysand.advert.support.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 推广单元接口实现
 *
 * Created By TINY
 * Create Time 2020/2/21
 **/
@Service
@Slf4j
public class AdUnitServiceImpl implements AdUnitService {

    /* 推广计划持久层对象 */
    private final PlanRepository planRepository;

    /* 推广单元持久层对象 */
    private final UnitRepository unitRepository;

    /* 推广关键字限制持久层对象 */
    private final KeywordRepository keywordRepository;

    /* 推广兴趣限制持久层对象 */
    private final InterestRepository interestRepository;

    /* 推广地域限制持久层对象 */
    private final DistrictRepository districtRepository;

    /* 广告持久层对象 */
    private final AdvertRepository advertRepository;

    /* 广告与推广单元关系持久层对象 */
    private final AdUnitRelRepository adUnitRelRepository;

    public AdUnitServiceImpl(PlanRepository planRepository,
                             UnitRepository unitRepository,
                             KeywordRepository keywordRepository,
                             InterestRepository interestRepository,
                             DistrictRepository districtRepository,
                             AdvertRepository advertRepository,
                             AdUnitRelRepository adUnitRelRepository) {
        this.planRepository = planRepository;
        this.unitRepository = unitRepository;
        this.keywordRepository = keywordRepository;
        this.interestRepository = interestRepository;
        this.districtRepository = districtRepository;
        this.advertRepository = advertRepository;
        this.adUnitRelRepository = adUnitRelRepository;
    }

    /**
     * 创建推广单元
     *
     * @param request 推广单元创建请求 {@link AdUnitRequest}
     * @return 推广单元响应对象 {@link AdUnitResponse}
     * @throws AdvertException 业务异常
     */
    @Override
    @Transactional
    public AdUnitResponse createAdUnit(AdUnitRequest request)
            throws AdvertException {

        if (!request.createValidate()) {
            throw new AdvertException(
                    SystemConstant.Error.REQUEST_PARAM_ERROR);
        }

        Optional<AdvertPlan> plan = planRepository
                .findById(request.getPlanId());

        if (!plan.isPresent()) {
            throw new AdvertException(SystemConstant.Error.RECORD_NOT_FOUND);
        }

        AdvertUnit advertUnit = unitRepository.findByPlanIdAndUnitName(
                request.getPlanId(), request.getUnitName()
        );

        if (advertUnit != null) {
            throw new AdvertException(
                    SystemConstant.Error.SAME_UNIT_PRESENT);
        }

        AdvertUnit newAdUnit = unitRepository.save(new AdvertUnit(
                request.getPlanId(), request.getUnitName(),
                request.getPositionType(), request.getBudget()
        ));

        return new AdUnitResponse(
                newAdUnit.getId(), newAdUnit.getUnitName());
    }

    /**
     * 创建推广单元关键字限制
     *
     * @param request 关键字限制请求对象 {@link AdKeywordRequest}
     * @return 关键字限制请求响应 {@link AdKeywordResponse}
     * @throws AdvertException 业务异常
     */
    @Override
    public AdKeywordResponse createUnitKeyword(AdKeywordRequest request)
            throws AdvertException {

        // 获取关键字中所有的推广单元id
        List<Long> unitIds = request.getUnitKeywords().stream()
                .map(AdKeywordRequest.Keyword::getUnitId)
                .collect(Collectors.toList());

        if (!isUnitExists(unitIds)) {
            throw new AdvertException(SystemConstant.Error.REQUEST_PARAM_ERROR);
        }

        // 保存后的关键字限制id
        List<Long> ids = Collections.emptyList();

        // 要保存的关键字限制
        List<AdUnitKeyWord> unitKeyWords = new ArrayList<>();

        if (!CollectionUtils.isEmpty(request.getUnitKeywords())) {
            request.getUnitKeywords().forEach(k -> unitKeyWords.add(
                    new AdUnitKeyWord(k.getUnitId(), k.getKeyword())
            ));

            ids = keywordRepository.saveAll(unitKeyWords).stream()
                    .map(AdUnitKeyWord::getId)
                    .collect(Collectors.toList());
        }
        return new AdKeywordResponse(ids);
    }

    /**
     * 创建推广单元兴趣限制
     *
     * @param request 兴趣限制请求对象 {@link AdInterestRequest}
     * @return 兴趣限制请求响应 {@link AdInterestResponse}
     * @throws AdvertException 业务异常
     */
    @Override
    public AdInterestResponse createUnitInterest(AdInterestRequest request)
            throws AdvertException {

        List<Long> unitIds = request.getInterests().stream()
                .map(AdInterestRequest.Interest::getUnitId)
                .collect(Collectors.toList());

        if (!isUnitExists(unitIds)) {
            throw new AdvertException(SystemConstant.Error.REQUEST_PARAM_ERROR);
        }

        // 要保存的兴趣限制
        List<AdUnitInterest> unitInterests = new ArrayList<>();
        request.getInterests().forEach(i -> unitInterests.add(
                new AdUnitInterest(i.getUnitId(), i.getItTag())
        ));

        // 保存后的兴趣限制id
        List<Long> ids = interestRepository.saveAll(unitInterests).stream()
                .map(AdUnitInterest::getId)
                .collect(Collectors.toList());

        return new AdInterestResponse(ids);
    }

    /**
     * 创建推广单元地域限制
     *
     * @param request 地域限制请求对象 {@link AdDistrictRequest}
     * @return 地域限制请求响应 {@link AdDistrictResponse}
     * @throws AdvertException 业务异常
     */
    @Override
    public AdDistrictResponse createUnitDistrict(AdDistrictRequest request)
            throws AdvertException {

        List<Long> unitIds = request.getDistricts().stream()
                .map(AdDistrictRequest.District::getUnitId)
                .collect(Collectors.toList());


        if (!isUnitExists(unitIds)) {
            throw new AdvertException(SystemConstant.Error.REQUEST_PARAM_ERROR);
        }

        // 要保存的地域限制
        List<AdUnitDistrict> unitDistricts = new ArrayList<>();
        request.getDistricts().forEach(d -> unitDistricts.add(
                new AdUnitDistrict(d.getUnitId(), d.getProvince(), d.getCity())
        ));

        // 保存后的地域限制id
        List<Long> ids = districtRepository.saveAll(unitDistricts).stream()
                .map(AdUnitDistrict::getId)
                .collect(Collectors.toList());

        return new AdDistrictResponse(ids);
    }

    /**
     * 创建广告与推广单元
     *
     * @param relRequest 广告与推广单元的关系创建请求对象 {@link AdUnitRelRequest}
     * @return 广告与推广单元的关系创建请求响应 {@link AdUnitRelResponse}
     * @throws AdvertException 业务异常
     */
    @Override
    public AdUnitRelResponse createAdUnitRel(AdUnitRelRequest relRequest)
            throws AdvertException {

        // 推广单元id
        List<Long> unitIds = relRequest.getUnitItems().stream()
                .map(AdUnitRelRequest.AdUnitItem::getUnitId)
                .collect(Collectors.toList());
        // 广告id
        List<Long> advertIds = relRequest.getUnitItems().stream()
                .map(AdUnitRelRequest.AdUnitItem::getCreativeId)
                .collect(Collectors.toList());

        if (!(isUnitExists(unitIds) && isAdvertExists(advertIds))) {
            throw new AdvertException(SystemConstant.Error.RECORD_NOT_FOUND);
        }

        List<AdvertUnitRelation> advertUnitRelations = new ArrayList<>();
        relRequest.getUnitItems().forEach(i -> advertUnitRelations.add(
                new AdvertUnitRelation(i.getCreativeId(), i.getUnitId())
        ));

        List<Long> ids = adUnitRelRepository.saveAll(advertUnitRelations).stream()
                .map(AdvertUnitRelation::getId)
                .collect(Collectors.toList());

        return new AdUnitRelResponse(ids);
    }

    /* 指定 unitIds 中的推广单元是否存在 */
    private boolean isUnitExists(List<Long> unitIds) {

        if (CollectionUtils.isEmpty(unitIds)) {
            return false;
        }

        return unitRepository.findAllById(unitIds).size()
                == new HashSet<>(unitIds).size();
    }

    /* 指定 id 的广告记录是否存在 */
    private boolean isAdvertExists(List<Long> advertIds) {
        if (CollectionUtils.isEmpty(advertIds)) {
            return false;
        }

        return advertRepository.findAllById(advertIds).size()
                == new HashSet<>(advertIds).size();
    }
}
